package org.cupk2.main.cecurity.controller;

import com.wf.captcha.SpecCaptcha;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.cupk2.auth.dto.MenusDto;
import org.cupk2.auth.service.ActionsServiceInter;
import org.cupk2.base.domain.CupkUserContext;
import org.cupk2.base.domain.CupkUserContextLoader;
import org.cupk2.base.jwt.CupkJwtClaims;
import org.cupk2.base.jwt.CupkJwtConfig;
import org.cupk2.base.jwt.CupkJwtUtils;
import org.cupk2.base.password.CupkPasswordEncoder;
import org.cupk2.main.cecurity.service.CupkUserOnlines;
import org.cupk2.main.cecurity.dto.TokensDto;
import org.cupk2.main.cecurity.utils.CupkLoginSafeUtils;
import org.cupk2.base.web.IpUtils;
import org.cupk2.main.cecurity.dto.LoginUserDto;
import org.cupk2.service.inter.CupkUserServiceInter;
import org.cupk2.tools.bean.CupkBeanUtils;
import org.cupk2.tools.caches.CupkCacheKeys;
import org.cupk2.tools.caches.CupkCaches;
import org.cupk2.tools.i18n.I18n;
import org.cupk2.tools.structure.CupkMaps;
import org.cupk2.tools.web.CupkResponseCode;
import org.cupk2.tools.web.CupkResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 用户登录
 */
@RestController
@Tag(name = "用户登录相关", description = "登录相关操作的API")
@RequestMapping("/api/login")
public class LoginController {
    @Autowired
    private CupkUserServiceInter cupkUserService;
    @Autowired
    private ActionsServiceInter actionsServiceImpl;
    @Autowired
    private CupkLoginSafeUtils cupkLoginSafeUtils;

    @Operation(summary = "获取当前用户", description = "未登录时返回空")
    @PostMapping(value = "/user")
    @ResponseBody
    public CupkResponseResult user(HttpServletRequest request) {
        if (CupkUserContextLoader.getCurrentUser() == null) {
            return new CupkResponseResult<Map>(CupkResponseCode.SUCESS);
        }
        CupkUserContext user = new CupkUserContext();
        CupkBeanUtils.copyProperties(CupkUserContextLoader.getCurrentUser(), user);
        user.setPassword("");
        List<MenusDto> menus = cupkUserService.getUserMenus(user, "FRAME");
        user.setFrameMenuNum(menus.size());
        return new CupkResponseResult<CupkUserContext>(CupkResponseCode.SUCESS, user);
    }

    @Operation(summary = "用戶预登录", description = "获取用户登录所必须的盐")
    @PostMapping(value = "/info")
    @ResponseBody
    public CupkResponseResult info(@RequestBody LoginUserDto user, HttpServletRequest request) {
        try {
        CupkUserContext dbuser = cupkUserService.getUserByLoginName(user.getLoginname());
        if (dbuser == null) {
            CupkPasswordEncoder passwordEncoder = new CupkPasswordEncoder();

            Map<String, Object> map = new HashMap<>();
            map.put("webcode", passwordEncoder.getSalt());//前端盐
            map.put("syscode", passwordEncoder.getSalt(user.getLoginname()).getVal());//数据库盐
            map.put("imgcode", (boolean) cupkLoginSafeUtils.isNeedImgCode(user.getLoginname()));//图形验证码，如果有的话
            return new CupkResponseResult<Map>(CupkResponseCode.SUCESS, map);
        } else {
            CupkPasswordEncoder passwordEncoder = new CupkPasswordEncoder();

            Map<String, Object> map = new HashMap<>();
            map.put("webcode", passwordEncoder.getSalt());//前端盐
            map.put("syscode", passwordEncoder.getDbSalt(dbuser.getPassword()));//数据库盐
            map.put("imgcode", (boolean) cupkLoginSafeUtils.isNeedImgCode(user.getLoginname()));//图形验证码，如果有的话
            return new CupkResponseResult<Map>(CupkResponseCode.SUCESS, map);
        }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(CupkPasswordEncoder.MATCHES_FALSEMSG);
        }
    }



    @Operation(summary = "用戶登录", description = "通过登录名和密码登录")
    @PostMapping(value = "/auth")
    @ResponseBody
    public CupkResponseResult login(@RequestBody LoginUserDto user, HttpServletRequest request) {



        if (!cupkLoginSafeUtils.validImgCode(user.getLoginname(), user.getImgcode())) {
            return new CupkResponseResult<Map>(CupkResponseCode.ERROR, I18n.msg(CupkLoginSafeUtils.MATCHES_FALSEMSG), null);
        }

        CupkUserContext dbuser = cupkUserService.getUserByLoginName(user.getLoginname());
        if (Objects.isNull(dbuser) || !dbuser.getState().equals("1")) {
            cupkLoginSafeUtils.registValidLoginResult(user.getLoginname(), false);

            throw new RuntimeException(I18n.msg(CupkPasswordEncoder.MATCHES_FALSEMSG));
        }

        CupkPasswordEncoder passwordEncoder = new CupkPasswordEncoder();
        if (!passwordEncoder.matches(user.getPassword(), CupkPasswordEncoder.getSaltByCode(user.getCode()), dbuser.getPassword())) {
            cupkLoginSafeUtils.registValidLoginResult(user.getLoginname(), false);

            throw new RuntimeException(I18n.msg(CupkPasswordEncoder.MATCHES_FALSEMSG));
        }

        cupkLoginSafeUtils.registValidLoginResult(user.getLoginname(), true);
        dbuser.setIp(IpUtils.getClientIp(request));

        Map<String, Object> claims = CupkJwtClaims.getInstance()
                .addUserKey(dbuser.getLoginname())
                .addFeild(CupkJwtConfig.ClaimsKey.LoginId, dbuser.initLoginid())
                .addFeild(CupkJwtConfig.ClaimsKey.IP, IpUtils.getClientIp(request))
                .getClaims();

        String jwt_auth = CupkJwtUtils.createAuthJwt(claims);
        String jwt_refresh = CupkJwtUtils.createRefreshJwt(claims);

        List<String> actionKeys = actionsServiceImpl.getActionsKeysByUserKey(user.getLoginname());
        dbuser.setActions(actionKeys);

        CupkUserOnlines.login(dbuser);
        return new CupkResponseResult<Map>(CupkResponseCode.SUCESS, CupkMaps.getInstance().put("token", jwt_auth + "||" + jwt_refresh).getMap());
    }

    @Operation(summary = "用戶注销", description = "注销当前用户")
    @GetMapping(value = "/out")
    @ResponseBody
    public CupkResponseResult out() {
        CupkUserContext user = CupkUserContextLoader.getCurrentUser();
        if (user == null) {
            return new CupkResponseResult<Map>(CupkResponseCode.WARN, "not login");
        }
        CupkUserOnlines.logout(user);
        return new CupkResponseResult<Map>(CupkResponseCode.SUCESS, "logout");
    }


    @GetMapping("/captcha/{loginname}")
    public void getCaptcha(@PathVariable String loginname, HttpServletRequest request, HttpServletResponse response) throws Exception {

        SpecCaptcha captcha = new SpecCaptcha(110, 40, 4);

        cupkLoginSafeUtils.registImgCode(loginname, captcha.text());
        captcha.setLen(4); // 设置验证码长度为3位

        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");

        captcha.out(response.getOutputStream());
    }


    @Operation(summary = "刷新token", description = "客户端请求刷新token授权")
    @PostMapping(value = "/rekey")
    @ResponseBody
    public CupkResponseResult rekey(@RequestBody TokensDto keys, HttpServletRequest request) {
        try {
            CupkJwtClaims clainms = CupkJwtUtils.parseJWT(keys.getLongKey());
            if (clainms == null) {
                return new CupkResponseResult<String>(CupkResponseCode.SUCESS, null, null);
            }
            if (clainms.get(CupkJwtConfig.ClaimsKey.TYPE).equals("2")) {
                if (IpUtils.getClientIp(request).equals(clainms.get(CupkJwtConfig.ClaimsKey.IP))) {

                    Integer loadNum = CupkCaches.getInstance().getCacheData(keys.getLongKey(), CupkCacheKeys.JWT_REFRESH_KES);
                    if (loadNum != null && loadNum > 10) {

                        return new CupkResponseResult<String>(CupkResponseCode.SUCESS, null, null);
                    } else {
                        if (loadNum == null) {
                            loadNum = 0;
                        }
                        CupkCaches.getInstance().putCacheData(keys.getLongKey(), ++loadNum, CupkCacheKeys.JWT_REFRESH_KES);
                    }


                    Map<String, Object> claims = CupkJwtClaims.getInstance()
                            .addUserKey((String) clainms.get(CupkJwtConfig.ClaimsKey.LoginName))
                            .addFeild(CupkJwtConfig.ClaimsKey.LoginId, (String) clainms.get(CupkJwtConfig.ClaimsKey.LoginId))
                            .addFeild(CupkJwtConfig.ClaimsKey.IP, (String) clainms.get(CupkJwtConfig.ClaimsKey.IP))
                            .getClaims();
                    String jwt = CupkJwtUtils.createAuthJwt(claims);
                    return new CupkResponseResult<String>(CupkResponseCode.SUCESS, null, jwt);
                } else {
                    throw new RuntimeException(I18n.msg("网络环境改变,请重新登录"));
                }
            }
            return new CupkResponseResult<String>(CupkResponseCode.SUCESS, null, null);
        } catch (Exception e) {
            throw e;
        }
    }
}
